using System;
using System.Collections.Generic;
using System.Text;
using Pacman.Simulator;
using NeuralNetwork;

namespace Pacman.Implementations
{
	public class DirectionDanger
	{
		public readonly Direction Direction;
		public readonly float Danger;

		public DirectionDanger(Direction direction, float danger) {
			this.Direction = direction;
			this.Danger = danger;
		}
	}

	public class DistanceNode
	{
		public readonly Node Node;
		public readonly float Distance;
		public readonly Direction Direction;
		public readonly int Time;

		public DistanceNode(Node node, float distance, Direction direction, int time) {
			this.Node = node;
			this.Distance = distance;
			if( this.Distance > 1.0f ) {
				this.Distance = 1.0f;
			}
			this.Direction = direction;
			this.Time = time;
		}
	}

	public class Sector
	{
		public static GameState GameState;
		private static int indexCount = 0;
		public readonly int Index;
		public readonly int X;
		public readonly int Y;
		public readonly int Width;
		public readonly int Height;
		public int TargetX;
		public int TargetY;
		private double danger = 0;
		public double Danger {
			get { return danger; }
			set { danger = value; }
		}
		private int nodes;
		public Network Network;

		private Sector(int x, int y, int width, int height) {
			this.X = x;
			this.Y = y;
			this.Width = width;
			this.Height = height;
			this.nodes = 0;
			for( int mx = x; mx < x + width; mx++ ) {
				for( int my = y; my < y + height; my++ ) {
					if( GameState.Map.Nodes[mx, my].Walkable ) {
						this.nodes++;
					}
				}
			}
			TargetX = x + (int)Math.Round(width / 2f);
			TargetY = y + (int)Math.Round(height / 2f);
			Index = indexCount++;
			string file = "sector" + Index + ".nn";
			Network = Network.Load(file);
		}

		public double[] GetDangerInputs() {
			double[] inputs = new double[4];
			for( int i = 0; i < 4; i++ ) {
				Simulator.Ghosts.Ghost ghost = GameState.Ghosts[i];
				inputs[i] = (int)Math.Abs(TargetX - ghost.Node.X) + (int)Math.Abs(TargetY - ghost.Node.Y);
				inputs[i] = inputs[i] / 40.0;
			}
			return inputs;
		}

		public double GetDanger() {
			danger = Network.GetOutputs(GetDangerInputs())[0];
			return danger;
		}

		public static Sector GetSector(int x, int y, int width, int height) {
			return new Sector(x, y, width, height);
		}

		public static Sector Contains(List<Sector> sectors, Node n) {
			foreach( Sector sector in sectors ) {
				if( sector.Contains(n) ) {
					return sector;
				}
			}
			return null;
		}

		public bool Contains(Node n) {
			return (n.X >= X && n.X <= X + Width && n.Y >= Y && n.Y <= Y + Height);
		}

		public double GetNormalizedDanger() {
			return danger / nodes;
		}
	}
}
